package implementation;



import static org.junit.Assert.*;

import org.junit.Test;
import java.io.IOException;

public class RobotTest {



	/*
	 * canPhysicallyReach() works properly.
	 * 
		@Test
		public final void canPhysicallyReach_TrueCase() {
			Board board = new Board(10, 15);
			Robot robot = new Robot(1, 20000.0);
			board.addRobot(5, 5, robot);
			boolean canIt = robot.canPhysicallyReach(3,6);
			assertEquals(true, canIt);
		}

		@Test
		public final void canPhysicallyReach_FalseCaseOccupiedPosition() {
			Board board = new Board(10, 15);
			Robot robot = new Robot(1, 20000.0);
			board.addRobot(5, 5, robot);
			Wall wall = new Wall();
			board.addWall(3, 6, wall);
			boolean canIt = robot.canPhysicallyReach(3,6);
			assertEquals(false, canIt);
		}

		@Test
		public final void canPhysicallyReach_FalseCaseInaccessiblePosition() {
			Board board = new Board(10, 15);
			Robot robot = new Robot(1, 20000.0);
			board.addRobot(5, 5, robot);
			for (int j=0; j<15; j++) {
				Wall wall = new Wall();
				board.addWall(7, j, wall);
			}
			boolean canIt = robot.canPhysicallyReach(9,9);
				assertEquals(false, canIt);
			}
	 */

	@Test
	public final void constructor_SingleCase() {
		Board board = new Board(20, 20);
		Robot robot = new Robot(3, 15000);
		board.addRobot(6, 7, robot);

		assertNotNull(robot);
		assertEquals(6, robot.getX());
		assertEquals(7, robot.getY());
		assertEquals(3, robot.getOrientation());
		assertEquals(15000.0, robot.getEnergy(), 0.1);
	}

	@Test
	public final void defaultConstructor_SingleCase() {
		Robot robot = new Robot();
		assertNotNull(robot);
		assertEquals(1, robot.getOrientation());
		assertEquals(0.0, robot.getEnergy(), 0.1);
	}

	//test isValidMAX_ENERGY
	@Test
	public final void isValidMAX_ENERGY_TrueCase() {
		assertTrue(Robot.isValidMaxEnergy(0.1));
	}

	@Test
	public final void isValidMAX_ENERGY_FalseCase() {
		assertFalse(Robot.isValidMaxEnergy(-0.1));
	}

	//test isValidEnergy
	@Test
	public final void isValidEnergy_TrueCase() {
		assertTrue(Robot.isValidEnergy(1000.0, 20000.0));
	}

	@Test
	public final void isValidEnergy_TrueCase0() {
		assertTrue(Robot.isValidEnergy(0.0, 20000.0));
	}

	@Test
	public final void isValidEnergy_TrueCaseMaxEnergy() {
		assertTrue(Robot.isValidEnergy(20000.0, 20000.0));
	}

	@Test
	public final void isValidEnergy_NegativeEnergy() {
		assertFalse(Robot.isValidEnergy(-1, 20000.0));
	}

	@Test
	public final void isValidEnergy_EnergyExceedingMAX_ENERGY() {
		assertFalse(Robot.isValidEnergy(20000.1, 20000.0));
	}

	//test isValidCoordinate
//	@Test
//	public final void isValidCoordinate_TrueCase0() {
//		assertTrue(Robot.isValidCoordinate(0, true));
//	}
//
//	@Test
//	public final void isValidCoordinate_TrueCaseMax() {
//		assertTrue(Robot.isValidCoordinate(Long.MAX_VALUE - 1, false));
//	}
//
//	@Test
//	public final void isValidCoordinate_NegativeCoordinate() {
//		assertFalse(Robot.isValidCoordinate(-1, false));
//	}
//
//	@Test
//	public final void isValidCoordinate_ExceedsMax() {
//		assertFalse(Robot.isValidCoordinate(Long.MAX_VALUE, false));
//	}

	//test isValidOrientation
	@Test
	public final void isValidOrientation_TrueCase0() {
		assertTrue(Robot.isValidOrientation(0));
	}

	@Test
	public final void isValidOrientation_TrueCase3() {
		assertTrue(Robot.isValidOrientation(3));
	}

	@Test
	public final void isValidOrientation_NegativeOrientation() {
		assertFalse(Robot.isValidOrientation(-1));
	}

	@Test
	public final void isValidOrientation_Exceeds3() {
		assertFalse(Robot.isValidOrientation(4));
	}

	//test hasEnergyToMove
	@Test
	public final void hasEnergyToMove_TrueCase() {
		assertTrue(Robot.hasEnergyToMove(500, 500));
	}

	@Test
	public final void hasEnergyToMove_FalseCase() {
		assertFalse(Robot.hasEnergyToMove(499, 500));
	}

	//test hasEnergyToTurn
	@Test
	public final void hasEnergyToTurn_TrueCase() {
		assertTrue(Robot.hasEnergyToTurn(100, 100));
	}

	@Test
	public final void hasEnergyToTurn_FalseCase() {
		assertFalse(Robot.hasEnergyToTurn(99, 100));
	}

	//test getEnergyAsFraction
	@Test
	public final void getEnergyAsFraction_TrueCase() {
		Robot robot = new Robot(0, 5000);
		assertEquals(0.25, robot.getEnergyAsFraction(), 0.1);
	}

	@Test
	public final void getEnergyAsFraction_TrueCase0() {
		Robot robot = new Robot(0, 0.0);
		assertEquals(0.0, robot.getEnergyAsFraction(), 0.1);
	}

	@Test
	public final void getEnergyAsFraction_TrueCase1() {
		Robot robot = new Robot(0, 20000.0);
		assertEquals(1.0, robot.getEnergyAsFraction(), 0.1);
	}

	//test recharge
	@Test
	public final void recharge_TrueCase() {
		Robot robot = new Robot(0, 5000);
		robot.recharge(5000);
		assertEquals(10000.0, robot.getEnergy(), 0.1);
	}

	/* Don't test this because there is a precondition.
	@Test
	public final void recharge_NegativeAmount() {
		IRobot robot = facade.createRobot(5, 7, 0, 5000);
		facade.recharge(robot, -5000);
		assertEquals(5000.0, facade.getEnergy(robot), 0.1);
	}

	@Test
	public final void recharge_ExeedsMAX_ENERGY() {
		IRobot robot = facade.createRobot(5, 7, 0, 5000);
		facade.recharge(robot, 16000);
		assertEquals(5000.0, facade.getEnergy(robot), 0.1);
	}
	 */

	/*
	 * 
	 * 
	 * Pickup tests
	 * 
	 * 
	 */

	// pickup a non existing battery. (should not be possible)
	@Test
	public final void pickup_NullBattery(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.pickUp(null);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertEquals(robot.getBatteries().size(), 0);
	}

	// pickup 1 battery at the location the robot is on.
	@Test
	public final void pickup_1Battery(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.pickUp(battery);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertFalse(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(robot.getBatteries().contains(battery));
	}

	// pickup 1 battery at a different location than the robot is on.
	@Test
	public final void pickup_otherLocation(){
		Board board = new Board(10, 10);
		long[] key = {5,5};
		long[] key2 = {6,6};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(6, 6, battery);

		assertNotNull(board.getLocation(key));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key2).getBatteries().contains(battery));

		robot.pickUp(battery);

		assertNotNull(board.getLocation(key));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key2).getBatteries().contains(battery));

		assertFalse(robot.getBatteries().contains(battery));
	}

	// pickup 1 battery at a different board but same position on that board as the robot is on.
	@Test
	public final void pickup_otherBoard(){
		Board board = new Board(10, 10);
		Board board2 = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		Battery battery = new Battery(2000.0, 500);
		board2.addBattery(5, 5, battery);

		assertNotNull(board.getLocation(key));
		assertNotNull(board2.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board2.getLocation(key).getBatteries().contains(battery));

		robot.pickUp(battery);

		assertNotNull(board.getLocation(key));
		assertNotNull(board2.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board2.getLocation(key).getBatteries().contains(battery));

		assertFalse(robot.getBatteries().contains(battery));
	}

	// pickup 3 batteries at the location the robot is on.
	@Test
	public final void pickup_3Batteries(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		Battery battery1 = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery1);
		Battery battery2 = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery2);
		Battery battery3 = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery3);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery1));
		assertTrue(board.getLocation(key).getBatteries().contains(battery2));
		assertTrue(board.getLocation(key).getBatteries().contains(battery3));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.pickUp(battery1);
		robot.pickUp(battery2);
		robot.pickUp(battery3);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertFalse(board.getLocation(key).getBatteries().contains(battery1));
		assertFalse(board.getLocation(key).getBatteries().contains(battery2));
		assertFalse(board.getLocation(key).getBatteries().contains(battery3));
		assertTrue(robot.getBatteries().contains(battery1));
		assertTrue(robot.getBatteries().contains(battery2));
		assertTrue(robot.getBatteries().contains(battery3));
	}

	/*
	 * 
	 * 
	 * drop tests
	 * 
	 * 
	 */

	// drop a non existing battery. (should not be possible)
	@Test
	public final void drop_NullBattery(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.drop(null);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertEquals(board.getLocation(key).getBatteries().size(), 0);
	}

	// drop a battery that is not carried.
	@Test
	public final void drop_notCarried(){
		Board board = new Board(10, 10);
		long[] key = {5,5};
		long[] key2 = {6,6};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(6, 6, battery);

		assertNotNull(board.getLocation(key));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key2).getBatteries().contains(battery));

		robot.drop(battery);

		assertNotNull(board.getLocation(key));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key2).getBatteries().contains(battery));

		assertEquals(board.getLocation(key).getBatteries().size(), 0);
	}

	// drop 1 battery.
	@Test
	public final void drop_1Battery(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.pickUp(battery);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertFalse(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(robot.getBatteries().contains(battery));

		robot.drop(battery);
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertFalse(robot.getBatteries().contains(battery));
	}

	// drop 3 batteries at the location the robot is on.
	@Test
	public final void drop_3Batteries(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		Battery battery1 = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery1);
		Battery battery2 = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery2);
		Battery battery3 = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery3);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery1));
		assertTrue(board.getLocation(key).getBatteries().contains(battery2));
		assertTrue(board.getLocation(key).getBatteries().contains(battery3));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.pickUp(battery1);
		robot.pickUp(battery2);
		robot.pickUp(battery3);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertFalse(board.getLocation(key).getBatteries().contains(battery1));
		assertFalse(board.getLocation(key).getBatteries().contains(battery2));
		assertFalse(board.getLocation(key).getBatteries().contains(battery3));
		assertTrue(robot.getBatteries().contains(battery1));
		assertTrue(robot.getBatteries().contains(battery2));
		assertTrue(robot.getBatteries().contains(battery3));

		robot.drop(battery1);
		robot.drop(battery2);
		robot.drop(battery3);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertTrue(board.getLocation(key).getBatteries().contains(battery1));
		assertTrue(board.getLocation(key).getBatteries().contains(battery2));
		assertTrue(board.getLocation(key).getBatteries().contains(battery3));
		assertFalse(robot.getBatteries().contains(battery1));
		assertFalse(robot.getBatteries().contains(battery2));
		assertFalse(robot.getBatteries().contains(battery3));
	}

	/*
	 * 
	 * 
	 * use tests
	 * 
	 * 
	 */

	// use 1 not effective battery (should not be possible)
	@Test
	public final void use_NullBattery(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 19000.0);
		board.addRobot(5, 5, robot);
		Battery battery = null;

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.use(battery);

		assertEquals(robot.getEnergy(), 19000.0, 0.1);
	}

	// use 1 battery the robot is carrying (use all energy in the battery)
	@Test
	public final void use_1BatteryAllEnergy(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 10000.0);
		board.addRobot(5, 5, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.pickUp(battery);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertFalse(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(robot.getBatteries().contains(battery));

		robot.use(battery);

		assertFalse(board.getLocation(key).getBatteries().contains(battery));
		assertFalse(robot.getBatteries().contains(battery));
		assertEquals(robot.getEnergy(), 12000.0, 0.1);
		assertTrue(battery.isTerminated());
		assertEquals(battery.getEnergy(), 0.0, 0.1);
	}

	// use 1 battery the robot is carrying (don't use all energy in the battery)
	@Test
	public final void use_1BatteryNotAllEnergy(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 19000.0);
		board.addRobot(5, 5, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.pickUp(battery);

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertFalse(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(robot.getBatteries().contains(battery));

		robot.use(battery);

		assertFalse(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(robot.getBatteries().contains(battery));
		assertEquals(robot.getEnergy(), 20000.0, 0.1);
		assertFalse(battery.isTerminated());
		assertEquals(battery.getEnergy(), 1000.0, 0.1);
	}

	// use 1 battery the robot is not carrying (should not be possible)
	@Test
	public final void use_1BatteryNotCarried(){
		Board board = new Board(10, 10);
		long[] key = {5,5};

		Robot robot = new Robot(1, 19000.0);
		board.addRobot(5, 5, robot);
		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 5, battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertTrue(board.getLocation(key).getRobots().contains(robot));

		robot.use(battery);

		assertTrue(board.getLocation(key).getBatteries().contains(battery));
		assertFalse(robot.getBatteries().contains(battery));
		assertEquals(robot.getEnergy(), 19000.0, 0.1);
		assertFalse(battery.isTerminated());
		assertEquals(battery.getEnergy(), 2000.0, 0.1);
	}


	/*
	 * 
	 * 
	 * shoot tests
	 * 
	 * 
	 */

	
	
	
	//shoot right at another robot
	//	@Test
	//	public final void shoot_noEnergy() {
	//		Board board = new Board(10, 10);
	//		long[] key = {5,5};
	//		long[] key2 = {6,5};
	//
	//		Robot robot = new Robot(1, 999.0);
	//		board.addRobot(5, 5, robot);
	//
	//		Robot robot2 = new Robot(1, 20000.0);
	//		board.addRobot(6, 5, robot2);
	//
	//		assertNotNull(board.getLocation(key));
	//		assertTrue(board.getLocation(key).getRobots().contains(robot));
	//		assertNotNull(board.getLocation(key2));
	//		assertTrue(board.getLocation(key2).getRobots().contains(robot2));
	//
	//		robot.shoot();
	//
	//		assertTrue(board.getLocation(key).getRobots().contains(robot));
	//		assertNotNull(board.getLocation(key2));
	//		assertTrue(board.getLocation(key2).getRobots().contains(robot2));
	//	}

	//shoot right at another robot
	@Test
	public final void shoot_right_SurvivingRobot() {
		Board board = new Board(10, 10);
		long[] key = {5,5};
		long[] key2 = {6,5};

		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);

		Robot robot2 = new Robot(1, 20000.0);
		board.addRobot(6, 5, robot2);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key2).getRobots().contains(robot2));

		robot.shoot();

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertEquals(robot2.getMAX_ENERGY(), 16000.0, 0.1);
		assertEquals(robot.getEnergy(), 19000.0, 0.1);
	}

	//shoot down at a robot (and kill it)
	@Test
	public final void shoot_down_KillRobot() {
		Board board = new Board(10, 10);
		long[] key = {5,5};
		long[] key2 = {5,6};

		Robot robot = new Robot(2, 20000.0);
		board.addRobot(5, 5, robot);

		Robot robot2 = new Robot(1, 20000.0);
		board.addRobot(5, 6, robot2);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key2).getRobots().contains(robot2));

		robot.shoot();
		robot.shoot();
		robot.shoot();
		robot.shoot();
		robot.shoot();

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertNull(board.getLocation(key2));
		assertTrue(robot2.isTerminated());
	}

	//shoot left at a battery
	@Test
	public final void shoot_left_Battery() {
		Board board = new Board(10, 10);
		long[] key = {5,5};
		long[] key2 = {4,5};

		Robot robot = new Robot(3, 20000.0);
		board.addRobot(5, 5, robot);

		Battery battery = new Battery(2000.0, 500);
		board.addBattery(4, 5, battery);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key2).getBatteries().contains(battery));

		robot.shoot();

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertEquals(battery.getEnergy(), 2500.0, 0.1);
		assertEquals(robot.getEnergy(), 19000.0, 0.1);
	}

	//shoot up at a RepairKit
	@Test
	public final void shoot_up_RepairKit() {
		Board board = new Board(10, 10);
		long[] key = {5,5};
		long[] key2 = {5,4};

		Robot robot = new Robot(0, 20000.0);
		board.addRobot(5, 5, robot);

		RepairKit repairKit = new RepairKit(2000.0, 500);
		board.addItem(5, 4, repairKit);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key2).getItems().contains(repairKit));

		robot.shoot();

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertEquals(repairKit.getEnergy(), 2500.0, 0.1);
		assertEquals(robot.getEnergy(), 19000.0, 0.1);
	}
	
	//Shoot SurpriseBox next to robot
	@Test
	public final void shoot_SurpriseBoxNextToRobot() {
		Board board = new Board(5,7);
		
		Robot robot = new Robot(0, 20000.0);
		board.addRobot(3, 5, robot);
		
		Robot robot2 = new Robot(1, 20000.0);
		board.addRobot(2, 2, robot2);
		
		SurpriseBox surpriseBox = new SurpriseBox(100);
		board.addItem(3, 2, surpriseBox);
		
		robot.shoot();
		
		assertEquals(19000.0, robot.getEnergy(), 0.1);
		assertEquals(surpriseBox.isTerminated(), true);
		assertEquals(16000.0, robot2.getMAX_ENERGY(), 0.1);
	}
	
	//Shoot Wall next to robot
	@Test
	public final void shoot_Wall() {
		Board board = new Board(5,7);

		Robot robot = new Robot(0, 20000.0);
		board.addRobot(3, 5, robot);
		
		Wall wall = new Wall();
		board.addWall(3, 2, wall);
		
		robot.shoot();
		
		assertEquals(19000.0, robot.getEnergy(), 0.1);
		assertEquals(wall.isTerminated(), false);
	}

	//shoot random at location
	@Test
	public final void shoot_random_BatteryAndRobot() {
		Board board = new Board(10, 10);
		long[] key = {5,5};
		long[] key2 = {5,4};

		Robot robot = new Robot(0, 20000.0);
		board.addRobot(5, 5, robot);

		Battery battery = new Battery(2000.0, 500);
		board.addBattery(5, 4, battery);

		Robot robot2 = new Robot(1, 20000.0);
		board.addRobot(5, 4, robot2);

		assertNotNull(board.getLocation(key));
		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key2).getBatteries().contains(battery));
		assertNotNull(board.getLocation(key2));
		assertTrue(board.getLocation(key2).getRobots().contains(robot2));

		robot.shoot();

		assertTrue(board.getLocation(key).getRobots().contains(robot));
		assertNotNull(board.getLocation(key2));
		assertTrue(((battery.getEnergy() == 2500.0) && !(robot2.getMAX_ENERGY() == 16000.0)) || (!(battery.getEnergy() == 2500.0) && (robot2.getMAX_ENERGY() == 16000.0)));
	}



	/*
	 * 
	 * 
	 * getImprovedEnergyToReach tests
	 * 
	 * 
	 */

	@Test
	public final void getImprovedEnergyToReach_thisRobot() {
		Board board = new Board(10, 15);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(5, 5, robot);
		long x = 5;
		long y = 5;
		double energyTo = robot.getImprovedEnergyToReach(x, y);
		assertEquals(0, energyTo, 0.1);
	}

	/*
	 * canPhysicallyReach() works properly.
	 * 
		@Test
		public final void canPhysicallyReach_TrueCase() {
			Board board = new Board(10, 15);
			Robot robot = new Robot(1, 20000.0);
			board.addRobot(5, 5, robot);
			boolean canIt = robot.canPhysicallyReach(3,6);
			assertEquals(true, canIt);
		}

		@Test
		public final void canPhysicallyReach_FalseCaseOccupiedPosition() {
			Board board = new Board(10, 15);
			Robot robot = new Robot(1, 20000.0);
			board.addRobot(5, 5, robot);
			Wall wall = new Wall();
			board.addWall(3, 6, wall);
			boolean canIt = robot.canPhysicallyReach(3,6);
			assertEquals(false, canIt);
		}

		@Test
		public final void canPhysicallyReach_FalseCaseInaccessiblePosition() {
			Board board = new Board(10, 15);
			Robot robot = new Robot(1, 20000.0);
			board.addRobot(5, 5, robot);
			for (int j=0; j<15; j++) {
				Wall wall = new Wall();
				board.addWall(7, j, wall);
			}
			boolean canIt = robot.canPhysicallyReach(9,9);
				assertEquals(false, canIt);
			}
	 */

	@Test
	public final void getImprovedEnergyToReach_TargetNotOnBoard() throws OutOfMemoryError {
		Board board = new Board(3, 4);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(2, 1, robot);
		long x = 4;
		long y = 3;
		double energyTo = robot.getImprovedEnergyToReach(x, y);
		assertEquals(-1, energyTo, 0.1);
	}

	@Test
	public final void getImprovedEnergyToReach_RobotNotOnBoard() throws OutOfMemoryError {
		Robot robot = new Robot(1, 20000.0);
		long x = 5;
		long y = 5;
		double energyTo = robot.getImprovedEnergyToReach(x, y);
		assertEquals(-1, energyTo, 0.1);
	}

	@Test
	public final void getImprovedEnergyToReach_cannotPhysicallyReach() throws OutOfMemoryError {
		Board board = new Board(40, 30);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(2, 1, robot);

		Wall wall1 = new Wall();
		board.addWall(30, 19, wall1);
		Wall wall2 = new Wall();
		board.addWall(29, 20, wall2);
		Wall wall3 = new Wall();
		board.addWall(31, 20, wall3);
		Wall wall4 = new Wall();
		board.addWall(30, 21, wall4);

		double energyTo = robot.getImprovedEnergyToReach(30, 20);
		assertEquals(-1, energyTo, 0.1);
	}

	@Test (expected = OutOfMemoryError.class)
	public final void getImprovedEnergyToReach_tooMuchMemory() throws OutOfMemoryError {
		Board board = new Board((long) (Integer.MAX_VALUE)*2, (long) (Integer.MAX_VALUE)*2);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(2, 1, robot);

		robot.getImprovedEnergyToReach(30, 20);

	}

	@Test
	public final void getImprovedEnergyToReach_hasInsufficientEnergy() throws OutOfMemoryError {
		Board board = new Board(5, 4);
		Robot robot = new Robot(1, 100.0);
		board.addRobot(2, 1, robot);

		double energyTo = robot.getImprovedEnergyToReach(1, 1);
		assertEquals(-1, energyTo, 0.1);
	}

	@Test
	public final void getImprovedEnergyToReach_NoObstacle_1Turn() throws OutOfMemoryError {
		Board board = new Board(5, 4);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(2, 1, robot);
		double energyTo = robot.getImprovedEnergyToReach(4, 3);
		assertEquals(2100, energyTo, 0.1);
	}

	@Test
	public final void getImprovedEnergyToReach_1Turn_Carrying1000gram() throws OutOfMemoryError {
		Board board = new Board(5, 4);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(2, 1, robot);

		Battery battery = new Battery(500.0, 1000);
		board.addBattery(2,1, battery);
		
		robot.pickUp(battery);
		double energyTo = robot.getImprovedEnergyToReach(4, 3);
		assertEquals(2300, energyTo, 0.1);
	}

	@Test
	public final void getImprovedEnergyToReach_1Turn_Carrying1000gram_Moving_PickingUp2000ExtraGram() throws OutOfMemoryError, InvalidLocationException {
		Board board = new Board(5, 6);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(2, 1, robot);
		
		Battery battery = new Battery(500.0, 1000);
		board.addBattery(2,1, battery);
		
		RepairKit repairKit = new RepairKit(1000.0, 2000);
		board.addItem(3, 1, repairKit);
		
		robot.pickUp(battery);
		robot.move();
		robot.pickUp(repairKit);
		
		double energyTo = robot.getImprovedEnergyToReach(4, 4);
		assertEquals(2700, energyTo, 0.1);
		
	}
	@Test
	public final void getImprovedEnergyToReach_3Obstacle_4Turns() throws OutOfMemoryError {
		Board board = new Board(5, 4);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(2, 1, robot);
		Wall wall1 = new Wall();
		board.addWall(4, 2, wall1);
		Wall wall2 = new Wall();
		board.addWall(3, 2, wall2);
		Wall wall3 = new Wall();
		board.addWall(2, 2, wall3);

		double energyTo = robot.getImprovedEnergyToReach(4, 3);
		assertEquals(3400, energyTo, 0.1);
	}

	@Test
	public final void getImprovedEnergyToReach_MultiplePaths() throws OutOfMemoryError {
		Board board = new Board(10, 10);
		Robot robot = new Robot(3, 20000.0);
		board.addRobot(4, 6, robot);

		int[][] walls = new int[10][10];

		for (int i=0;i<4;i++) {
			walls[i][0]=1;
		}
		for (int i=5;i<9;i++) {
			walls[i][1]=1;
		}
		walls[8][2]=1;
		for (int i=1;i<5;i++) {
			walls[i][4]=1;
		}
		walls[7][4]=1;
		walls[8][4]=1;
		for (int i=3;i<7;i++) {
			walls[i][8]=1;
		}
		for (int i=0;i<4;i++) {
			walls[i][9]=1;
		}
		walls[6][9]=1;
		for (int i=5;i<8;i++) {
			walls[1][i]=1;
		}
		for (int i=5;i<9;i++) {
			walls[8][i]=1;
		}
		for (int i=0; i<10; i++) {
			for (int j=0; j<10; j++) {
				Wall wall = new Wall();
				if (walls[i][j] == 1) {
					board.addWall(i, j, wall);
				}
			}
		}

		double energyTo = robot.getImprovedEnergyToReach(3, 2);
		assertEquals(3900, energyTo, 0.1);
	}

	// test move
	@Test
	public void testMove_right() throws InvalidLocationException {
		Board board = new Board(100, 200);
		Robot robot = new Robot(1, 5000);
		board.addRobot(5, 7, robot);

		robot.move();
		assertEquals(6, robot.getX());
		assertEquals(7, robot.getY());
		assertEquals(1, robot.getOrientation());
		assertEquals(5000 - 500, robot.getEnergy(), 0.1);
	}

	@Test
	public void testMove_down() throws InvalidLocationException {
		Board board = new Board(100, 200);
		Robot robot = new Robot(2, 5000);
		board.addRobot(5, 7, robot);
		robot.move();
		assertEquals(5, robot.getX());
		assertEquals(8, robot.getY());
		assertEquals(2, robot.getOrientation());
		assertEquals(5000 - 500, robot.getEnergy(), 0.1);
	}

	@Test
	public void testMove_left() throws InvalidLocationException {
		Board board = new Board(100, 200);
		Robot robot = new Robot(3, 5000);
		board.addRobot(5, 7, robot);robot.move();
		assertEquals(4, robot.getX());
		assertEquals(7, robot.getY());
		assertEquals(3, robot.getOrientation());
		assertEquals(5000 - 500, robot.getEnergy(), 0.1);
	}

	@Test
	public void testMove_up() throws InvalidLocationException {
		Board board = new Board(100, 200);
		Robot robot = new Robot(0, 5000);
		board.addRobot(5, 7, robot);
		robot.move();
		assertEquals(5, robot.getX());
		assertEquals(6, robot.getY());
		assertEquals(0, robot.getOrientation());
		assertEquals(5000 - 500, robot.getEnergy(), 0.1);
	}

//	@Test
//	public void testMoveInsufficientEnergy() throws InvalidLocationException{
//		Board board = new Board(100, 200);
//		Robot robot = new Robot(1, 250);
//		board.addRobot(0, 0, robot);
//		robot.move();
//		assertEquals(0, robot.getX());
//		assertEquals(0, robot.getY());
//		assertEquals(1, robot.getOrientation());
//		assertEquals(250, robot.getEnergy(), 0.1);
//	}

	@Test (expected=InvalidLocationException.class)
	public void testMove_IllegalCase() throws InvalidLocationException {
		Board board = new Board(100, 200);
		Robot robot = new Robot(0, 5000);
		board.addRobot(5, 0, robot);
		robot.move();
	}

	@Test (expected=InvalidLocationException.class)
	public void testMove_IllegalCase2() throws InvalidLocationException {
		Board board = new Board(100, 200);
		Robot robot = new Robot(3, 5000);
		board.addRobot(0, 5, robot);
		robot.move();
	}

	//test moveNextTo (not complete)
	
	@Test
	public void moveNextTo_noObstacles() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		Board board = new Board(5,7);
		
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(1, 1, robot);
		
		Robot robot2 = new Robot(2, 20000.0);
		board.addRobot(4, 5, robot2);
		
		robot.moveNextTo(robot2);
		assertTrue(robot.getX() == 3 && robot.getY() == 5 && robot.getEnergy() == 16900.0 && robot.getOrientation() == 2);
		assertTrue(robot2.getX() == 4 && robot2.getY() == 5 && robot2.getEnergy() == 20000.0);
	}
	
	@Test
	public void moveNextTo_rowOfObstacles() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		Board board = new Board(5,7);
		
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(1, 1, robot);
		
		Robot robot2 = new Robot(2, 20000.0);
		board.addRobot(4, 5, robot2);
		
		for (int i=0; i <5; i++) {
			Wall wall = new Wall();
			board.addWall(i, 3, wall);
		}
		
		robot.moveNextTo(robot2);
		assertEquals(1,robot.getX());
		assertEquals(2, robot.getY());
		assertEquals(19400.0, robot.getEnergy(), 0.1);
		assertEquals(2, robot.getOrientation());
		
		assertEquals(1, robot2.getX());
		assertEquals(4, robot2.getY());
		assertEquals(17800.0, robot2.getEnergy(), 19300.0);
		assertEquals(0, robot2.getOrientation());
		
	}
	
	@Test
	public void moveNextTo_complexButReachableObstaclesPath() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		Board board = new Board(5,7);
		
		Robot robot = new Robot(2, 20000.0);
		board.addRobot(2, 2, robot);
		
		Robot robot2 = new Robot(2, 20000.0);
		board.addRobot(4, 5, robot2);
		
		for (int i=1; i <6; i++) {
			Wall wall = new Wall();
			board.addWall(1, i, wall);
		}
		
		Wall wall2 = new Wall();
		board.addWall(2, 3, wall2);
		
		Wall wall3 = new Wall();
		board.addWall(3, 3, wall3);
		
		Wall wall4 = new Wall();
		board.addWall(4, 4, wall4);
		
		Wall wall5 = new Wall();
		board.addWall(3, 6, wall5);
		
		robot.moveNextTo(robot2);
		assertEquals(2,robot.getX());
		assertEquals(2, robot.getY());
		assertEquals(20000.0, robot.getEnergy(), 0.1);
		assertEquals(2, robot.getOrientation());
		
		assertEquals(2, robot2.getX());
		assertEquals(1, robot2.getY());
		assertEquals(14600.0, robot2.getEnergy(), 19300.0);
		assertEquals(2, robot2.getOrientation());
		
		}
	
	@Test
	public void moveNextTo_complexUnreachableObstaclesPath() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		Board board = new Board(5,7);
		
		Robot robot = new Robot(2, 20000.0);
		board.addRobot(2, 2, robot);
		
		Robot robot2 = new Robot(2, 20000.0);
		board.addRobot(4, 5, robot2);
		
		for (int i=1; i <7; i++) {
			Wall wall = new Wall();
			board.addWall(1, i, wall);
		}
		
		for (int i=3; i <6; i++) {
			Wall wall = new Wall();
			board.addWall(2, i, wall);
		}
		
		for (int i=3; i <5; i++) {
			Wall wall = new Wall();
			board.addWall(3, i, wall);
		}
		
		for (int i=3; i <5; i++) {
			Wall wall = new Wall();
			board.addWall(4, i, wall);
		}
		
		robot.moveNextTo(robot2);
		
		assertEquals(0,robot.getX());
		assertEquals(6, robot.getY());
		assertEquals(14600.0, robot.getEnergy(), 0.1);
		assertEquals(2, robot.getOrientation());
		
		assertEquals(2, robot2.getX());
		assertEquals(6, robot2.getY());
		assertEquals(18400.0, robot2.getEnergy(), 19300.0);
		assertEquals(3, robot2.getOrientation());
		
		}
	
	@Test
	public void moveNextTo_complexReachableObstaclesPath_Robot1NoEnergy() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		Board board = new Board(5,7);
		
		Robot robot = new Robot(2, 0.0);
		board.addRobot(2, 2, robot);
		
		Robot robot2 = new Robot(2, 20000.0);
		board.addRobot(4, 5, robot2);
		
		for (int i=1; i <6; i++) {
			Wall wall = new Wall();
			board.addWall(1, i, wall);
		}
		
		for (int i=3; i <6; i++) {
			Wall wall = new Wall();
			board.addWall(2, i, wall);
		}

		for (int i=3; i <5; i++) {
			Wall wall = new Wall();
			board.addWall(3, i, wall);
		}

		for (int i=3; i <5; i++) {
			Wall wall = new Wall();
			board.addWall(4, i, wall);
		}

		robot.moveNextTo(robot2);

		assertEquals(2,robot.getX());
		assertEquals(2, robot.getY());
		assertEquals(0.0, robot.getEnergy(), 0.1);
		assertEquals(2, robot.getOrientation());

		assertEquals(2, robot2.getX());
		assertEquals(1, robot2.getY());
		assertEquals(12600.0, robot2.getEnergy(), 19300.0);
		assertEquals(2, robot2.getOrientation());

	}
	
	@Test
	public void moveNextTo_complexReachableObstaclesPath_Robot2NoEnergy() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		Board board = new Board(5,7);
		
		Robot robot = new Robot(2, 20000.0);
		board.addRobot(2, 2, robot);
		
		Robot robot2 = new Robot(2, 0.0);
		board.addRobot(4, 5, robot2);
		
		for (int i=1; i <6; i++) {
			Wall wall = new Wall();
			board.addWall(1, i, wall);
		}
		
		for (int i=3; i <6; i++) {
			Wall wall = new Wall();
			board.addWall(2, i, wall);
		}

		for (int i=3; i <5; i++) {
			Wall wall = new Wall();
			board.addWall(3, i, wall);
		}

		for (int i=3; i <5; i++) {
			Wall wall = new Wall();
			board.addWall(4, i, wall);
		}

		robot.moveNextTo(robot2);

		assertEquals(4,robot.getX());
		assertEquals(6, robot.getY());
		assertEquals(12500.0, robot.getEnergy(), 0.1);
		assertEquals(1, robot.getOrientation());

		assertEquals(4, robot2.getX());
		assertEquals(5, robot2.getY());
		assertEquals(0.0, robot2.getEnergy(), 19300.0);
		assertEquals(2, robot2.getOrientation());

	}
	
	@Test (expected = IllegalArgumentException.class)
	public void moveNextTo_IllegalCase_Argument() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		Board board1 = new Board(10, 10);
		Robot robot1 = new Robot(2, 2000.0);
		board1.addRobot(2, 4, robot1);
		
		Board board2 = new Board(20, 5);
		Robot robot2 = new Robot(2, 2000.0);
		board2.addRobot(2, 4, robot2);
		
		robot1.moveNextTo(robot2);
	}
	
	@Test (expected = NullPointerException.class)
	public void moveNextTo_IllegalCase_Null() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		Board board1 = new Board(10, 10);
		Robot robot1 = new Robot(2, 2000.0);
		board1.addRobot(2, 4, robot1);
		
		Robot robot2 = null;
		
		robot1.moveNextTo(robot2);
	}
	
	@Test (expected = OutOfMemoryError.class)
	public void moveNextTo_IllegalCase_Memory() throws IllegalArgumentException, NullPointerException, OutOfMemoryError {
		
		Board board = new Board((Long.MAX_VALUE-2), (Long.MAX_VALUE-2));
		
		Robot robot = new Robot(2, 20000.0);
		board.addRobot(2, 2, robot);
		
		Robot robot2 = new Robot(2, 0.0);
		board.addRobot(4, 5, robot2);
		
		robot.moveNextTo(robot2);
	}

	//test turnClockwise
	@Test
	public void turnClockwise_1() {
		Robot robot = new Robot(1, 5000);
		robot.turnClockwise();
		assertEquals(2, robot.getOrientation());
		assertEquals(5000-100, robot.getEnergy(), 0.1);
	}

	@Test
	public void turnClockwise_3() {
		Robot robot = new Robot(3, 5000);
		robot.turnClockwise();
		assertEquals(0, robot.getOrientation());
		assertEquals(5000-100, robot.getEnergy(), 0.1);
	}

	/*
	 * Assertion errors cannot be tested, as they are supposed not to be encountered.
	 */
//	@Test
//	public void turnClockwise_InsufficientEnergy() {
//		Robot robot = new Robot(0, 50);
//		robot.turnClockwise();
//		assertEquals(0, robot.getOrientation());
//		assertEquals(50, robot.getEnergy(), 0.1);
//	}

	//test turnCounterClockwise
	@Test
	public void turnCounterClockwise_3() {
		Robot robot = new Robot(3, 5000);
		robot.turnCounterClockwise();
		assertEquals(2, robot.getOrientation());
		assertEquals(5000-100, robot.getEnergy(), 0.1);
	}

	@Test
	public void turnCounterClockwise_0() {
		Robot robot = new Robot( 0, 5000);
		robot.turnCounterClockwise();
		assertEquals(3, robot.getOrientation());
		assertEquals(5000-100, robot.getEnergy(), 0.1);
	}

//	@Test
//	public void turnCounterClockwise_InsufficientEnergy() {
//		Robot robot = new Robot(0, 50);
//		robot.turnClockwise();
//		assertEquals(0, robot.getOrientation());
//		assertEquals(50, robot.getEnergy(), 0.1);
//	}

	/*
	 * Program tests.
	 */
	@Test
	public final void testProgram_cowboy(){
		long[] key = {1,4};
		Board board = new Board(10,10);
		Robot robot = new Robot(1, 20000.0);
		board.addRobot(1, 1, robot);
		Robot target = new Robot(1, 20000.0);
		board.addRobot(1, 4, target);
		try {
			robot.getProgram().loadProgram("cowboy.prog");
		} catch (IOException e) {
			System.err.println(e.getMessage());
		}
		robot.getProgram().runner();
		assertEquals(robot.getOrientation(),2);
		assertFalse(board.getLocation(key).getRobots().isEmpty());
		robot.getProgram().runner();
		assertEquals(target.getMAX_ENERGY(), 16000.0, 0.1);
		board.addWall(1, 3, new Wall());
		robot.getProgram().runner();
		assertEquals(robot.getOrientation(),3);
	}
	
	@Test
	public final void testProgram_gump(){
		Board board = new Board(10,10);
		Robot robot = new Robot(1, 1000.0);
		board.addRobot(1, 1, robot);
		
		try {
			robot.getProgram().loadProgram("gump.prog");
		} catch (IOException e) {
			System.err.println(e.getMessage());
		}
		robot.getProgram().runner();
		assertEquals(robot.getX(),2);
		
		robot.getProgram().runner();
		assertEquals(robot.getX(),2);
	}
	
	@Test
	public final void testProgram_example(){
		Board board = new Board(10,10);
		Robot robot = new Robot(1, 1000.0);
		board.addRobot(1, 1, robot);
		
		try {
			robot.getProgram().loadProgram("example.prog");
		} catch (IOException e) {
			System.err.println(e.getMessage());
		}
		robot.getProgram().runner();
		assertEquals(robot.getX(),2);
		
		robot.getProgram().runner();
		assertEquals(robot.getOrientation(),2);

		robot.getProgram().runner();
		assertEquals(robot.getY(),1);
		assertEquals(robot.getX(),2);
		assertEquals(robot.getOrientation(),2);
	}
	
	@Test
	public final void testProgram_customexample(){
		Board board = new Board(10,10);
		Robot robot = new Robot(2, 5000.0);
		Robot target = new Robot(2, 1000.0);
		board.addRobot(1, 1, robot);
		board.addRobot(4, 1, target);
		board.addWall(1, 2, new Wall());
		
		try {
			robot.getProgram().loadProgram("customexample.prog");
		} catch (IOException e) {
			System.err.println(e.getMessage());
		}
		robot.getProgram().runner();
		assertEquals(robot.getOrientation(),1);

		robot.getProgram().runner();
		assertEquals(robot.getY(),1);
		assertEquals(robot.getX(),2);
		assertEquals(robot.getOrientation(),1);
	}
}